/**********************************************************************
*  Copyright (c) 2007 - Victor Jacobs - victor.jacobs@gmail.com
*
*  Permission is hereby granted, free of charge, to any person
*  obtaining a copy of this software and associated documentation
*  files (the "Software"), to deal in the Software without
*  restriction, including without limitation the rights to use,
*  copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the
*  Software is furnished to do so, subject to the following
*  conditions:
*
*  The above copyright notice and this permission notice shall be
*  included in all copies or substantial portions of the Software.
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
*  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
*  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
*  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
*  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
*  OTHER DEALINGS IN THE SOFTWARE.
**********************************************************************/

using System;
using System.Collections.Generic;
using System.Text;

namespace Vj.GA.Functions
{
    public class FunctionGrabber
    {

        public static double XYSquared(double[] x)
        {
            if (x.Length != 2)
                throw new Exception("Invalid argument");
            
            //double z = -(x[0] * x[0] + x[1]*x[1])/700*Math.Sin(x[0]*x[1]);

            //y*y = (R-r*r+z*z)^.5 - x*x
            //double R = 10;
            //double r = 10;
            
            //double i1 = Math.Pow( (R-r*r+x[1]*x[1]/10), 0.5) ;
            //double z = Math.Pow((i1 - x[0]*x[0]/10), 0.5);
            //return z;

            //double z = x[0] * x[0] + x[1] * x[1] * x[1]/11000;100.0 

            //double z;
            //if (x[0] != 0 && x[1] != 0)
            //    z = x[0] * x[1] / 100;
            //else
            //    z = double.NaN;

            //double z = x[0] * (x[0] - 50) * (x[0] - 100) / 10000.0 + (x[1] - 50) * (x[0] - x[1]) * x[0] / 10000.0;
                        
            //double z = Math.Pow(2.0*Math.Sin(x[0] * x[0] + x[1] * x[1]), 7);

            double z = 50*Math.Cos(Math.Abs(x[0]) + Math.Abs(x[1]));
            //X - double z = 100.0-100.0*Math.Exp(Math.Sin(x[0]) / x[1]);

            //double z = 25*Math.Tanh((double)x[0] * (double)x[1]);
            return z;       
        }

        public static double Dome(double[] x)
        {
            double z = -(x[0] * x[0] + x[1] * x[1]) / 100.0 + 50.0;
            return z;
        }

        public static double Cone(double[] x)
        {
            double z = 50 - Math.Pow(((x[0]) * (x[0]) + (x[1]) * (x[1])), 0.5);
            return z;
        }

        public static double SaddlePoint(double[] x)
        {
            double z = (x[0] * x[0] - x[1] * x[1]) / 100.0;
            return z;
        }

        public static double Linear1(double[] x)
        {
            return (x[0] + x[1])/20;
        }

        public static double Linear2(double[] x)
        {
            
            return 0.0;
        }

        public static double Linear3(double[] x)
        {
            //(0.4^2-(0.6-(x^2+y^2)^0.5)^2)^0.5
            double i1 = Math.Pow((x[0] * x[0] + x[1] * x[1]), 0.5);
            double i2 = Math.Pow((0.6-i1),2);
            double z = Math.Pow((0.4*0.4-i2),0.5);
            return z;
        }

        //public static double HimmelBlau(double[] x)
        //{
        //    double z = 800 - Math.Pow((x[0] * x[0] + x[1] - 11), 2) -
        //        Math.Pow((x[0] + x[1] * x[1] - 7), 2);
        //    return z;
        //}

        //public static double MultiPeaks(double[] x)
        //{
        //    double z = x[0] * Math.Sin(4.0 * Math.PI * x[0]) - x[1] * Math.Sin(4.0 * Math.PI * x[1] + Math.PI) + 1.0;
        //    return z;
        //}

        public static double Wavy(double[] x)
        {
            double z = 25 * (Math.Cos(1.0 / 16.0 * x[0]) + Math.Cos(1.0 / 16.0 * x[1]));
            return z;
        }

        public static double VeryWavy(double[] x)
        {
            double z = 10.0 * Math.Cos(10 * x[0] * x[0] + x[1] * x[1]);
            return z;
        }

    }
}
